/**
 * @name async_api_postmain
 * @description 從 Postman 獲取 API 集合，並轉換為 TypeScript API 客戶端程式碼
 * @author gongben@filbetph.com
 * @version 1.0.0
 * @since 2025-03-23
 */
import dayjs from "dayjs"
import * as fs from "node:fs"

const CONFIG = {
    // 從 Postman 獲取 API 集合的 URL
    api_url:
        "https://api.postman.com/collections/42969266-bac271e9-d253-4ffd-8705-d7b676f6419f?access_key=PMAT-01JRMPMXKMCQQCEZZFPWVY0S91",
    // 生成的 API 類別名稱
    api_name: "postman_api_filbet_client_v1",
    // 生成的 API 程式碼輸出路徑 (改為數組)
    output_dirs: [
        "./src/apis",
        "./tools/generated_apis",
        // 可加入更多輸出路徑
    ],
}

// 程序執行起始目錄
const _dir_runtime = process.cwd()
// 本文件的目錄
const _dir_current = process.argv[1]?.replace(/(.*)(\/.+\.(ts|js))/, "$1")
if (!_dir_current) {
    throw new Error(`目錄不存在`)
}
// 臨時目錄
const _dir_tmp = `${_dir_current}/_tmp`
// 臨時目錄下的 postman 目錄
const _dir_tmp_postman = `${_dir_tmp}/postman`
// 臨時目錄下的 postman 目錄下的 collections 目錄
const _dir_tmp_postman_collections = `${_dir_tmp_postman}/collections`

import CollectionJsonSample from "./json/sample_postman_collection.json"
import SwaggerJsonSample from "./json/sample_postman_swagger.json"
type CollectionType = typeof CollectionJsonSample
type SwaggerType = typeof SwaggerJsonSample

async function main() {
    console.log("開始從 Postman 獲取 API 集合...")
    const response = (await fetchPostmanCollection(CONFIG.api_url)) as CollectionType
    console.log("成功獲取 Postman API 集合")

    // 建立集合目錄
    const _dir_collection = `${_dir_tmp_postman_collections}/${response.collection.info.name}`
    fs.mkdirSync(_dir_collection, { recursive: true })

    // 生成檔案名稱（基於更新時間）
    const collection_filename = dayjs(response.collection.info.updatedAt).format("YYYYMMDDHHmmss")
    const collection_filepath = `${_dir_collection}/${collection_filename}.json`

    // 儲存 Postman 集合
    console.log("正在儲存 Postman 集合...")
    console.log(`輸出路徑: ${collection_filepath}`)
    fs.writeFileSync(collection_filepath, JSON.stringify(response, null, 2))
    console.log("Postman 集合儲存完成")

    // 轉換為 Swagger 格式
    console.log("開始轉換為 Swagger 格式...")
    const swagger_filename = `${collection_filename}_swagger`
    const swagger = (await convertPostmanCollectionToSwagger(response.collection)) as SwaggerType
    // 修正 page 与 page_size 的类型
    fixPaginationParameterTypes(swagger)
    const swagger_filepath = `${_dir_collection}/${swagger_filename}.json`

    // 儲存 Swagger 文件
    console.log(`輸出路徑: ${swagger_filepath}`)
    fs.writeFileSync(swagger_filepath, JSON.stringify(swagger, null, 2))
    console.log("Swagger 轉換完成並儲存")

    // 生成 TypeScript API 程式碼
    console.log("開始生成 TypeScript API...")
    for (const dir of CONFIG.output_dirs) {
        const output_dir = `${_dir_runtime}/${dir}`
        // 確保目錄存在
        fs.mkdirSync(output_dir, { recursive: true })

        await convertSwaggerToApi({
            name: CONFIG.api_name,
            input: swagger_filepath,
            output: output_dir,
        })
        console.log(`TypeScript API 已生成至: ${output_dir}`)
    }
    console.log("所有轉換程序完成")
}

/**
 * 從 Postman API 獲取集合數據
 * @param url Postman API URL，包含集合 ID 和訪問金鑰
 * @returns Promise<CollectionType> Postman 集合數據
 */
async function fetchPostmanCollection(url: string) {
    console.log("正在從 Postman API 獲取數據...")
    const response = await fetch(url)
    const data = await response.json()
    console.log("Postman API 數據獲取完成")
    return data
}

import { transpile } from "postman2openapi"
/**
 * 將 Postman 集合轉換為 Swagger/OpenAPI 格式
 * @param collection Postman 集合對象
 * @returns Promise<SwaggerType> 轉換後的 Swagger 文件
 */
async function convertPostmanCollectionToSwagger(collection: CollectionType["collection"]) {
    console.log("正在轉換 Postman 集合為 Swagger 格式...")
    const swagger = await transpile(collection)
    console.log("Swagger 格式轉換完成")
    return swagger
}
/**
 * 修正分页参数 page 和 page_size 的类型為 number（原本是 string）
 * @param swagger Swagger 文件
 */
const forcedIntegerParams = ["page", "page_size"] //需要将参数类型转换成number的
function fixPaginationParameterTypes(swagger: SwaggerType): SwaggerType {
    const paths = swagger.paths as Record<string, Record<string, any>>

    for (const path of Object.keys(paths)) {
        const methods = paths[path]
        if (!methods) continue
        for (const method of Object.keys(methods ?? {})) {
            const operation = methods[method] as {
                parameters?: Array<{
                    name: string
                    in: string
                    schema?: { type?: string; format?: string }
                }>
            }

            if (!operation?.parameters) continue

            for (const param of operation.parameters) {
                if (param.in === "query" && forcedIntegerParams.includes(param.name)) {
                    param.schema = {
                        type: "integer",
                        format: "int32",
                    }
                }
            }
        }
    }

    return swagger
}

import { generateApi } from "swagger-typescript-api"
/**
 * 將 Swagger 文件轉換為 TypeScript API 客戶端程式碼
 * @param options 生成選項，包含輸入輸出路徑等配置
 * @returns Promise<void>
 */
type GenerateApiOptions = Parameters<typeof generateApi>[0]
async function convertSwaggerToApi(options?: Partial<GenerateApiOptions>) {
    console.log("正在生成 TypeScript API 客戶端程式碼...")
    const api = await generateApi({
        httpClientType: "axios", // 使用 axios 作為 HTTP 客戶端
        apiClassName: "PostmanApi", // 生成的 API 類別名稱
        singleHttpClient: true, // 使用單一 HTTP 客戶端實例
        moduleNameIndex: 0, // 模組名稱索引
        moduleNameFirstTag: true, // 使用第一個標籤作為模組名稱
        ...(options as GenerateApiOptions),
    })
    console.log("TypeScript API 客戶端程式碼生成完成")
    return api
}

/**
 * 格式化端點名稱
 * @param endpoint 端點名稱
 * @returns 格式化後的端點名稱
 * @description 將端點名稱中的空格轉換為底線
 * @example
 * formatEndPointName("Send SMS OTP") => "SendSmsOtp"
 */
async function formatEndPointName(endpoint: string) {
    return endpoint
        .split(" ")
        .map((word) => word.charAt(0).toUpperCase() + word.slice(1))
        .join("")
}

main()
